package com.hice.demo.java.concurrent.delayqueue;

import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.DelayQueue;

/**
 * 业务场景二：具有过期时间的缓存
 * 向缓存添加内容时，给每一个key设定过期时间，系统自动将超过过期时间的key清除。
 * 这个场景中几个点需要注意：
 * 当向缓存中添加key-value对时，如果这个key在缓存中存在并且还没有过期，
 * 需要用这个key对应的新过期时间
 * 为了能够让DelayQueue将其已保存的key删除，
 * 需要重写实现Delayed接口添加到DelayQueue的DelayedItem的hashCode函数和equals函数
 * 当缓存关闭，监控程序也应关闭，因而监控线程应当用守护线程
 *
 * @author hyson
 * @create 2017-03-13 11:03
 */
public class Cache<K, V> {

    public ConcurrentHashMap<K, V> map = new ConcurrentHashMap<>();
    public DelayQueue<DelayedItem<K>> queue = new DelayQueue<>();

    public void put(K k, V v, long liveTime) {
        V v2 = map.put(k, v);
        DelayedItem<K> tmpItem = new DelayedItem<K>(k, liveTime);
        if (v2 != null) {
            queue.remove(tmpItem);
        }
        queue.put(tmpItem);
    }

    public Cache() {
        Thread t = new Thread() {
            @Override
            public void run() {
                dameonCheckOverdueKey();
            }
        };
        t.setDaemon(true);
        t.start();
    }

    public void dameonCheckOverdueKey() {
        while (true) {
            DelayedItem<K> delayedItem = queue.poll();
            if (delayedItem != null) {
                map.remove(delayedItem.getT());
                System.out.println(System.nanoTime() + " remove " + delayedItem.getT() + " from cache");
            }
            try {
                Thread.sleep(300);
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    }

    /**
     * TODO
     *
     * @param args 2014-1-11 上午11:30:36
     * @throws InterruptedException
     * @author:孙振超
     */
    public static void main(String[] args) throws InterruptedException {
        Random random = new Random();
        int cacheNumber = 10;
        int liveTime = 0;
        Cache<String, Integer> cache = new Cache<>();

        for (int i = 0; i < cacheNumber; i++) {
            liveTime = random.nextInt(3000);
            System.out.println(i + "  " + liveTime);
            cache.put(i + "", i, random.nextInt(liveTime));
            if (random.nextInt(cacheNumber) > 7) {
                liveTime = random.nextInt(3000);
                System.out.println(i + "  " + liveTime);
                cache.put(i + "", i, random.nextInt(liveTime));
            }
        }

        Thread.sleep(3000);
        System.out.println();
    }
}
